package com.sky.service.rider.impl;

import com.sky.constant.MessageConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.exception.CodeExpiredException;
import com.sky.exception.CourierNotExistException;
import com.sky.exception.DataException;
import com.sky.mapper.common.*;
import com.sky.pojo.Courier;
import com.sky.pojo.CourierTradeOrder;
import com.sky.pojo.Orders;
import com.sky.pojo.ShotUri;
import com.sky.properties.ShortProperties;
import com.sky.result.Result;
import com.sky.service.rider.CourierService;
import com.sky.service.user.OrderDispatchService;
import com.sky.shoturi.ShortUriGenerator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Service
@Transactional(readOnly = true)
public class CourierServiceImpl implements CourierService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CourierMapper courierMapper;

    @Autowired
    private TradeOrderMapper tradeOrderMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ShortUriGenerator shortUriGenerator;

    @Autowired
    private ShortProperties shortProperties;

    @Autowired
    private ShortUrlInfoMapper shortUrlInfoMapper;

    @Autowired
    private OrderDispatchService orderDispatchService;

    /**
     * 骑手登录
     *
     * @param loginDTO
     * @return
     */
    @Override
    public Result<Courier> login(UserLoginDTO loginDTO) {
        //1.校验参数
        if(null == loginDTO ||
                StringUtils.isEmpty(loginDTO.getTelephone()) ||
                StringUtils.isEmpty(loginDTO.getCode())){
            throw new DataException(MessageConstant.DATA_ERROR);
        }

        //2. 通过手机号码构建redis的key 然后查询验证码 如果验证码不存在则抛出异常
        String redisKey = "login:code:" + loginDTO.getTelephone();
        Object code = redisTemplate.opsForValue().get(redisKey);
        if(null == code){
            throw new CodeExpiredException("验证码已经过期了");
        }

        if(!loginDTO.getCode().equals(code.toString())){
            throw new CodeExpiredException("验证码输入错误");
        }

        //3. 通过手机号码查询骑手信息 如果没有查询到抛出异常
        Courier courier = courierMapper.findByPhone(loginDTO.getTelephone());
        if(null == courier){
            throw new CourierNotExistException("快递员不存在，请检查手机号");
        }
        //4. 返回骑手信息

        return Result.success(courier);
    }

    /**
     * 骑手接单
     *
     * @param courierId
     * @param tradeNo
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public Result<String> receivingOrder(Long courierId, String tradeNo) {
        //1. 参数校验
        if(null == courierId || null == tradeNo){
            throw new DataException(MessageConstant.DATA_ERROR);
        }

        //2. 根据运单号查询运单数据 然后判断运单是否存在 如果不存在则抛出异常
        CourierTradeOrder tradeOrder = tradeOrderMapper.selectByTradeNo(tradeNo);
        if(null == tradeOrder){
            throw new DataException(MessageConstant.DATA_ERROR);
        }

        //3. 更新运单的状态
        tradeOrder.setWaybillStatus(CourierTradeOrder.DELIVORING);
        tradeOrderMapper.updateStatusById(tradeOrder);

        //4. 更新订单的状态
        Orders orders = new Orders();
        orders.setNumber(tradeOrder.getOrderNumber());
        orders.setStatus(Orders.TOBEPICKEDUP);

        orderMapper.updateStatusByNumber(orders);

        //5. 发送短信告诉用户骑手已经接单 同时短信中会带一个网址 用户请求该网址就可以看到最新的快递数据
        createShortUrl(courierId, tradeNo);
       // System.out.println("http://localhost:8080/rider.html?tradeNo="+tradeNo+"&courierId=" + courierId +"&expire=null");

        //6. 返回结果
        return Result.success();
    }

    /**
     * 骑手转单求助
     *
     * @param tradeNo
     * @param courierId
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public Result<Courier> transferOrderToTaskPool(String tradeNo, Long courierId) {
        Courier courier = orderDispatchService.dispatchCourier(null, tradeNo, courierId);
        return Result.success(courier);
    }


    /**
     * 生成短链接 并发送短信
     * @param courierId
     * @param tradeNo
     */
    private void createShortUrl(Long courierId, String tradeNo) {
        //1. 生成短链接的编码
        String code = "";
        while(true){
            code = shortUriGenerator.creatKey();
            int hashcode = code.hashCode();
            Long index = 0L;

            if(hashcode < 0){
                index = Math.abs(hashcode) + 2147483648l;
            }else {
                index = (long) hashcode;
            }

            Boolean flag = redisTemplate.opsForValue().getBit("short_url", index);
            if(!flag){
                redisTemplate.opsForValue().setBit("short_url", index, true);
                break;
            }
        }

        //2. 生成短链接
        StringBuilder sb = new StringBuilder();
        sb.append(shortProperties.getDomainName())
                .append(shortProperties.getShortUrlPrefix())
                .append(code);

        //3. 生成完整的链接
        StringBuilder fullSB = new StringBuilder();
        fullSB.append(shortProperties.getDomainName())
                .append(shortProperties.getRealResource())
                .append("?tradeNo=" + tradeNo)
                .append("&courierId=" + courierId);

        //4. 保存短链接和完整链接到数据库构建他们的对应关系
        ShotUri shortUrl = ShotUri.builder()
                .fullUrl(fullSB.toString())
                .shotUrl(sb.toString())
                .tradeNo(tradeNo)
                .shortCode(code)
                .expireTime(LocalDateTime.now()) //这个字段没有使用 随意给的一个时间
                .build();
        shortUrlInfoMapper.insert(shortUrl);

        //5. 发送短信
        System.out.println(sb.toString());

    }
}
